/*
** Dis.c
** handle disassembly window and process.
*/

#include "dis6502.h"

typedef enum   MODE_ENUM
               {
               MODE_IMMEDIATE,
               MODE_ABSOLUTE,
               MODE_ZERO_PAGE,
               MODE_ACCUMULATOR,
               MODE_IMPLIED,
               MODE_INDEXED_INDIRECT,
               MODE_INDIRECT_INDEXED,
               MODE_ZERO_PAGE_X,
               MODE_ZERO_PAGE_Y,
               MODE_ABSOLUTE_X,
               MODE_ABSOLUTE_Y,
               MODE_RELATIVE,
               MODE_INDIRECT
               } MODE_ENUM;

typedef struct OPCODE
               {
               char           szName[4];
               BOOL           bIllegal;
               MODE_ENUM      wMode;
               } OPCODE;

static BYTE    *pDisNextByte;
static BYTE    *pDisNextType;
static BOOL    bDisNewSegment;
static WORD    wDisSegmentSize;
static BYTE    cDisByteType;
static BYTE    cDisDumpType;
static WORD    wDisNbBytes;
static OPCODE  TabOpcode[256] =
               {
      /* 00 */ { "BRK", FALSE, MODE_IMPLIED          },
      /* 01 */ { "ORA", FALSE, MODE_INDEXED_INDIRECT },
      /* 02 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 03 */ { "slo", TRUE,  MODE_INDIRECT_INDEXED },
      /* 04 */ { "dop", TRUE,  MODE_ZERO_PAGE        },
      /* 05 */ { "ORA", FALSE, MODE_ZERO_PAGE        },
      /* 06 */ { "ASL", FALSE, MODE_ZERO_PAGE        },
      /* 07 */ { "slo", TRUE,  MODE_ZERO_PAGE        },
      /* 08 */ { "PHP", FALSE, MODE_IMPLIED          },
      /* 09 */ { "ORA", FALSE, MODE_IMMEDIATE        },
      /* 0A */ { "ASL", FALSE, MODE_ACCUMULATOR      },
      /* 0B */ { "aac", TRUE,  MODE_IMMEDIATE        },
      /* 0C */ { "top", TRUE,  MODE_ABSOLUTE         },
      /* 0D */ { "ORA", FALSE, MODE_ABSOLUTE         },
      /* 0E */ { "ASL", FALSE, MODE_ABSOLUTE         },
      /* 0F */ { "slo", TRUE,  MODE_ABSOLUTE         },
      /* 10 */ { "BPL", FALSE, MODE_RELATIVE         },
      /* 11 */ { "ORA", FALSE, MODE_INDIRECT_INDEXED },
      /* 12 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 13 */ { "slo", TRUE,  MODE_INDEXED_INDIRECT },
      /* 14 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* 15 */ { "ORA", FALSE, MODE_ZERO_PAGE_X      },
      /* 16 */ { "ASL", FALSE, MODE_ZERO_PAGE_X      },
      /* 17 */ { "slo", TRUE,  MODE_ZERO_PAGE_X      },
      /* 18 */ { "CLC", FALSE, MODE_IMPLIED          },
      /* 19 */ { "ORA", FALSE, MODE_ABSOLUTE_Y       },
      /* 1A */ { "nop", TRUE,  MODE_IMPLIED          },
      /* 1B */ { "slo", TRUE,  MODE_ABSOLUTE_Y       },
      /* 1C */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* 1D */ { "ORA", FALSE, MODE_ABSOLUTE_X       },
      /* 1E */ { "ASL", FALSE, MODE_ABSOLUTE_X       },
      /* 1F */ { "slo", TRUE,  MODE_ABSOLUTE_X       },
      /* 20 */ { "JSR", FALSE, MODE_ABSOLUTE         },
      /* 21 */ { "AND", FALSE, MODE_INDEXED_INDIRECT },
      /* 22 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 23 */ { "rla", TRUE,  MODE_INDEXED_INDIRECT },
      /* 24 */ { "BIT", FALSE, MODE_ZERO_PAGE        },
      /* 25 */ { "AND", FALSE, MODE_ZERO_PAGE        },
      /* 26 */ { "ROL", FALSE, MODE_ZERO_PAGE        },
      /* 27 */ { "rla", TRUE,  MODE_ZERO_PAGE        },
      /* 28 */ { "PLP", FALSE, MODE_IMPLIED          },
      /* 29 */ { "AND", FALSE, MODE_IMMEDIATE        },
      /* 2A */ { "ROL", FALSE, MODE_ACCUMULATOR      },
      /* 2B */ { "aac", TRUE,  MODE_IMMEDIATE        },
      /* 2C */ { "BIT", FALSE, MODE_ABSOLUTE         },
      /* 2D */ { "AND", FALSE, MODE_ABSOLUTE         },
      /* 2E */ { "ROL", FALSE, MODE_ABSOLUTE         },
      /* 2F */ { "rla", TRUE,  MODE_ABSOLUTE         },
      /* 30 */ { "BMI", FALSE, MODE_RELATIVE         },
      /* 31 */ { "AND", FALSE, MODE_INDIRECT_INDEXED },
      /* 32 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 33 */ { "rla", TRUE,  MODE_INDIRECT_INDEXED },
      /* 34 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* 35 */ { "AND", FALSE, MODE_ZERO_PAGE_X      },
      /* 36 */ { "ROL", FALSE, MODE_ZERO_PAGE_X      },
      /* 37 */ { "rla", TRUE,  MODE_ZERO_PAGE_X      },
      /* 38 */ { "SEC", FALSE, MODE_IMPLIED          },
      /* 39 */ { "AND", FALSE, MODE_ABSOLUTE_Y       },
      /* 3A */ { "nop", TRUE,  MODE_IMPLIED          },
      /* 3B */ { "rla", TRUE,  MODE_ABSOLUTE_Y       },
      /* 3C */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* 3D */ { "AND", FALSE, MODE_ABSOLUTE_X       },
      /* 3E */ { "ROL", FALSE, MODE_ABSOLUTE_X       },
      /* 3F */ { "rla", TRUE,  MODE_ABSOLUTE_X       },
      /* 40 */ { "RTI", FALSE, MODE_IMPLIED          },
      /* 41 */ { "EOR", FALSE, MODE_INDEXED_INDIRECT },
      /* 42 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 43 */ { "sre", TRUE,  MODE_INDEXED_INDIRECT },
      /* 44 */ { "dop", TRUE,  MODE_ZERO_PAGE        },
      /* 45 */ { "EOR", FALSE, MODE_ZERO_PAGE        },
      /* 46 */ { "LSR", FALSE, MODE_ZERO_PAGE        },
      /* 47 */ { "sre", TRUE,  MODE_ZERO_PAGE        },
      /* 48 */ { "PHA", FALSE, MODE_IMPLIED          },
      /* 49 */ { "EOR", FALSE, MODE_IMMEDIATE        },
      /* 4A */ { "LSR", FALSE, MODE_ACCUMULATOR      },
      /* 4B */ { "asr", TRUE,  MODE_IMMEDIATE        },
      /* 4C */ { "JMP", FALSE, MODE_ABSOLUTE         },
      /* 4D */ { "EOR", FALSE, MODE_ABSOLUTE         },
      /* 4E */ { "LSR", FALSE, MODE_ABSOLUTE         },
      /* 4F */ { "sre", TRUE,  MODE_ABSOLUTE         },
      /* 50 */ { "BVC", FALSE, MODE_RELATIVE         },
      /* 51 */ { "EOR", FALSE, MODE_INDIRECT_INDEXED },
      /* 52 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 53 */ { "sre", TRUE,  MODE_INDIRECT_INDEXED },
      /* 54 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* 55 */ { "EOR", FALSE, MODE_ZERO_PAGE_X      },
      /* 56 */ { "LSR", FALSE, MODE_ZERO_PAGE_X      },
      /* 57 */ { "sre", TRUE,  MODE_ZERO_PAGE_X      },
      /* 58 */ { "CLI", FALSE, MODE_IMPLIED          },
      /* 59 */ { "EOR", FALSE, MODE_ABSOLUTE_Y       },
      /* 5A */ { "nop", TRUE,  MODE_IMPLIED          },
      /* 5B */ { "sre", TRUE,  MODE_ABSOLUTE_Y       },
      /* 5C */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* 5D */ { "EOR", FALSE, MODE_ABSOLUTE_X       },
      /* 5E */ { "LSR", FALSE, MODE_ABSOLUTE_X       },
      /* 5F */ { "sre", TRUE,  MODE_ABSOLUTE_X       },
      /* 60 */ { "RTS", FALSE, MODE_IMPLIED          },
      /* 61 */ { "ADC", FALSE, MODE_INDEXED_INDIRECT },
      /* 62 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 63 */ { "rra", TRUE,  MODE_INDEXED_INDIRECT },
      /* 64 */ { "dop", TRUE,  MODE_ZERO_PAGE        },
      /* 65 */ { "ADC", FALSE, MODE_ZERO_PAGE        },
      /* 66 */ { "ROR", FALSE, MODE_ZERO_PAGE        },
      /* 67 */ { "rra", TRUE,  MODE_ZERO_PAGE        },
      /* 68 */ { "PLA", FALSE, MODE_IMPLIED          },
      /* 69 */ { "ADC", FALSE, MODE_IMMEDIATE        },
      /* 6A */ { "ROR", FALSE, MODE_ACCUMULATOR      },
      /* 6B */ { "arr", TRUE,  MODE_IMMEDIATE        },
      /* 6C */ { "JMP", FALSE, MODE_INDIRECT         },
      /* 6D */ { "ADC", FALSE, MODE_ABSOLUTE         },
      /* 6E */ { "ROR", FALSE, MODE_ABSOLUTE         },
      /* 6F */ { "rra", TRUE,  MODE_ABSOLUTE         },
      /* 70 */ { "BVS", FALSE, MODE_RELATIVE         },
      /* 71 */ { "ADC", FALSE, MODE_INDIRECT_INDEXED },
      /* 72 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 73 */ { "rra", TRUE,  MODE_INDIRECT_INDEXED },
      /* 74 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* 75 */ { "ADC", FALSE, MODE_ZERO_PAGE_X      },
      /* 76 */ { "ROR", FALSE, MODE_ZERO_PAGE_X      },
      /* 77 */ { "rra", TRUE,  MODE_ZERO_PAGE_X      },
      /* 78 */ { "SEI", FALSE, MODE_IMPLIED          },
      /* 79 */ { "ADC", FALSE, MODE_ABSOLUTE_Y       },
      /* 7A */ { "nop", TRUE,  MODE_IMPLIED          },
      /* 7B */ { "rra", TRUE,  MODE_ABSOLUTE_Y       },
      /* 7C */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* 7D */ { "ADC", FALSE, MODE_ABSOLUTE_X       },
      /* 7E */ { "ROR", FALSE, MODE_ABSOLUTE_X       },
      /* 7F */ { "rra", TRUE,  MODE_ABSOLUTE_X       },
      /* 80 */ { "dop", TRUE,  MODE_IMMEDIATE        },
      /* 81 */ { "STA", FALSE, MODE_INDEXED_INDIRECT },
      /* 82 */ { "dop", TRUE,  MODE_IMMEDIATE        },
      /* 83 */ { "aax", TRUE,  MODE_INDEXED_INDIRECT },
      /* 84 */ { "STY", FALSE, MODE_ZERO_PAGE        },
      /* 85 */ { "STA", FALSE, MODE_ZERO_PAGE        },
      /* 86 */ { "STX", FALSE, MODE_ZERO_PAGE        },
      /* 87 */ { "aax", TRUE,  MODE_ZERO_PAGE        },
      /* 88 */ { "DEY", FALSE, MODE_IMPLIED          },
      /* 89 */ { "dop", TRUE,  MODE_IMMEDIATE        },
      /* 8A */ { "TXA", FALSE, MODE_IMPLIED          },
      /* 8B */ { "xaa", TRUE,  MODE_IMMEDIATE        },
      /* 8C */ { "STY", FALSE, MODE_ABSOLUTE         },
      /* 8D */ { "STA", FALSE, MODE_ABSOLUTE         },
      /* 8E */ { "STX", FALSE, MODE_ABSOLUTE         },
      /* 8F */ { "aax", TRUE,  MODE_ABSOLUTE         },
      /* 90 */ { "BCC", FALSE, MODE_RELATIVE         },
      /* 91 */ { "STA", FALSE, MODE_INDIRECT_INDEXED },
      /* 92 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* 93 */ { "axa", TRUE,  MODE_INDIRECT_INDEXED },
      /* 94 */ { "STY", FALSE, MODE_ZERO_PAGE_X      },
      /* 95 */ { "STA", FALSE, MODE_ZERO_PAGE_X      },
      /* 96 */ { "STX", FALSE, MODE_ZERO_PAGE_X      },
      /* 97 */ { "aax", TRUE,  MODE_ZERO_PAGE_Y      },
      /* 98 */ { "TYA", FALSE, MODE_IMPLIED          },
      /* 99 */ { "STA", FALSE, MODE_ABSOLUTE_Y       },
      /* 9A */ { "TXS", FALSE, MODE_IMPLIED          },
      /* 9B */ { "xas", TRUE,  MODE_ABSOLUTE_Y       },
      /* 9C */ { "sya", TRUE,  MODE_ABSOLUTE_X       },
      /* 9D */ { "STA", FALSE, MODE_ABSOLUTE_X       },
      /* 9E */ { "sxa", TRUE,  MODE_ABSOLUTE_Y       },
      /* 9F */ { "axa", TRUE,  MODE_ABSOLUTE_Y       },
      /* A0 */ { "LDY", FALSE, MODE_IMMEDIATE        },
      /* A1 */ { "LDA", FALSE, MODE_INDEXED_INDIRECT },
      /* A2 */ { "LDX", FALSE, MODE_IMMEDIATE        },
      /* A3 */ { "lax", TRUE,  MODE_INDEXED_INDIRECT },
      /* A4 */ { "LDY", FALSE, MODE_ZERO_PAGE        },
      /* A5 */ { "LDA", FALSE, MODE_ZERO_PAGE        },
      /* A6 */ { "LDX", FALSE, MODE_ZERO_PAGE        },
      /* A7 */ { "lax", TRUE,  MODE_ZERO_PAGE        },
      /* A8 */ { "TAY", FALSE, MODE_IMPLIED          },
      /* A9 */ { "LDA", FALSE, MODE_IMMEDIATE        },
      /* AA */ { "TAX", FALSE, MODE_IMPLIED          },
      /* AB */ { "atx", TRUE,  MODE_IMPLIED          },
      /* AC */ { "LDY", FALSE, MODE_ABSOLUTE         },
      /* AD */ { "LDA", FALSE, MODE_ABSOLUTE         },
      /* AE */ { "LDX", FALSE, MODE_ABSOLUTE         },
      /* AF */ { "lax", TRUE,  MODE_ABSOLUTE         },
      /* B0 */ { "BCS", FALSE, MODE_RELATIVE         },
      /* B1 */ { "LDA", FALSE, MODE_INDIRECT_INDEXED },
      /* B2 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* B3 */ { "lax", TRUE,  MODE_INDIRECT_INDEXED },
      /* B4 */ { "LDY", FALSE, MODE_ZERO_PAGE_X      },
      /* B5 */ { "LDA", FALSE, MODE_ZERO_PAGE_X      },
      /* B6 */ { "LDX", FALSE, MODE_ZERO_PAGE_X      },
      /* B7 */ { "lax", TRUE,  MODE_ZERO_PAGE_Y      },
      /* B8 */ { "CLV", FALSE, MODE_IMPLIED          },
      /* B9 */ { "LDA", FALSE, MODE_ABSOLUTE_Y       },
      /* BA */ { "TSX", FALSE, MODE_IMPLIED          },
      /* BB */ { "lar", TRUE,  MODE_ABSOLUTE_Y       },
      /* BC */ { "LDY", FALSE, MODE_ABSOLUTE_X       },
      /* BD */ { "LDA", FALSE, MODE_ABSOLUTE_X       },
      /* BE */ { "LDX", FALSE, MODE_ABSOLUTE_Y       },
      /* BF */ { "lax", TRUE,  MODE_ABSOLUTE_Y       },
      /* C0 */ { "CPY", FALSE, MODE_IMMEDIATE        },
      /* C1 */ { "CMP", FALSE, MODE_INDEXED_INDIRECT },
      /* C2 */ { "dop", TRUE,  MODE_IMMEDIATE        },
      /* C3 */ { "dcp", TRUE,  MODE_INDEXED_INDIRECT },
      /* C4 */ { "CPY", FALSE, MODE_ZERO_PAGE        },
      /* C5 */ { "CMP", FALSE, MODE_ZERO_PAGE        },
      /* C6 */ { "DEC", FALSE, MODE_ZERO_PAGE        },
      /* C7 */ { "dcp", TRUE,  MODE_ZERO_PAGE        },
      /* C8 */ { "INY", FALSE, MODE_IMPLIED          },
      /* C9 */ { "CMP", FALSE, MODE_IMMEDIATE        },
      /* CA */ { "DEX", FALSE, MODE_IMPLIED          },
      /* CB */ { "axs", TRUE,  MODE_IMMEDIATE        },
      /* CC */ { "CPY", FALSE, MODE_ABSOLUTE         },
      /* CD */ { "CMP", FALSE, MODE_ABSOLUTE         },
      /* CE */ { "DEC", FALSE, MODE_ABSOLUTE         },
      /* CF */ { "dcp", TRUE,  MODE_ABSOLUTE         },
      /* D0 */ { "BNE", FALSE, MODE_RELATIVE         },
      /* D1 */ { "CMP", FALSE, MODE_INDIRECT_INDEXED },
      /* D2 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* D3 */ { "dcp", TRUE,  MODE_INDIRECT_INDEXED },
      /* D4 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* D5 */ { "CMP", FALSE, MODE_ZERO_PAGE_X      },
      /* D6 */ { "DEC", FALSE, MODE_ZERO_PAGE_X      },
      /* D7 */ { "dcp", TRUE,  MODE_ZERO_PAGE_X      },
      /* D8 */ { "CLD", FALSE, MODE_IMPLIED          },
      /* D9 */ { "CMP", FALSE, MODE_ABSOLUTE_Y       },
      /* DA */ { "nop", TRUE,  MODE_IMPLIED          },
      /* DB */ { "dcp", TRUE,  MODE_ABSOLUTE_Y       },
      /* DC */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* DD */ { "CMP", FALSE, MODE_ABSOLUTE_X       },
      /* DE */ { "DEC", FALSE, MODE_ABSOLUTE_X       },
      /* DF */ { "dcp", TRUE,  MODE_ABSOLUTE_X       },
      /* E0 */ { "CPX", FALSE, MODE_IMMEDIATE        },
      /* E1 */ { "SBC", FALSE, MODE_INDEXED_INDIRECT },
      /* E2 */ { "dop", TRUE,  MODE_IMMEDIATE        },
      /* E3 */ { "isc", TRUE,  MODE_INDEXED_INDIRECT },
      /* E4 */ { "CPX", FALSE, MODE_ZERO_PAGE        },
      /* E5 */ { "SBC", FALSE, MODE_ZERO_PAGE        },
      /* E6 */ { "INC", FALSE, MODE_ZERO_PAGE        },
      /* E7 */ { "isc", TRUE,  MODE_ZERO_PAGE        },
      /* E8 */ { "INX", FALSE, MODE_IMPLIED          },
      /* E9 */ { "SBC", FALSE, MODE_IMMEDIATE        },
      /* EA */ { "NOP", FALSE, MODE_IMPLIED          },
      /* EB */ { "sbc", TRUE,  MODE_IMMEDIATE        },
      /* EC */ { "CPX", FALSE, MODE_ABSOLUTE         },
      /* ED */ { "SBC", FALSE, MODE_ABSOLUTE         },
      /* EE */ { "INC", FALSE, MODE_ABSOLUTE         },
      /* EF */ { "isc", TRUE,  MODE_ABSOLUTE         },
      /* F0 */ { "BEQ", FALSE, MODE_RELATIVE         },
      /* F1 */ { "SBC", FALSE, MODE_INDIRECT_INDEXED },
      /* F2 */ { "kil", TRUE,  MODE_IMPLIED          },
      /* F3 */ { "isc", TRUE,  MODE_INDIRECT_INDEXED },
      /* F4 */ { "dop", TRUE,  MODE_ZERO_PAGE_X      },
      /* F5 */ { "SBC", FALSE, MODE_ZERO_PAGE_X      },
      /* F6 */ { "INC", FALSE, MODE_ZERO_PAGE_X      },
      /* F7 */ { "isc", TRUE,  MODE_ZERO_PAGE_X      },
      /* F8 */ { "SED", FALSE, MODE_IMPLIED          },
      /* F9 */ { "SBC", FALSE, MODE_ABSOLUTE_Y       },
      /* FA */ { "nop", TRUE,  MODE_IMPLIED          },
      /* FB */ { "isc", TRUE,  MODE_ABSOLUTE_Y       },
      /* FC */ { "top", TRUE,  MODE_ABSOLUTE_X       },
      /* FD */ { "SBC", FALSE, MODE_ABSOLUTE_X       },
      /* FE */ { "INC", FALSE, MODE_ABSOLUTE_X       },
      /* FF */ { "isc", TRUE,  MODE_ABSOLUTE_X       }
               };

void DisRegister(HANDLE hInstance)
{
     /*
     ** reset variables
     */
     memset(Disasm, 0, sizeof(Disasm));
     DisInit(hInstance);
}

/*
** find the last buffer of a list.
*/
static DIS_BUFFER *DisFindLastBuffer(WORD wType)
{
DIS_BUFFER *pLast;

     /*
     ** add this buffer to the end of the list.
     */
     if (pLast = Disasm[wType])
          {
          while (pLast->pNext)
               pLast = pLast->pNext;
          return pLast;
          }
     return NULL;
}

/*
** allocate a buffer and add it at the end of a list.
*/
static DIS_BUFFER *DisAllocBuffer(HWND hWnd, WORD wType)
{
DIS_BUFFER *pBuf;
DIS_BUFFER *pLast;

     /*
     ** allocate a new buffer and initialize variables.
     */
     if ((pBuf = (DIS_BUFFER *) MemoryAlloc(sizeof(DIS_BUFFER) + 32)) == NULL)
          {
          Error(hWnd, IDS_ERR_NO_LABEL_MEMORY, "Could not allocate memory for equates !");
          return NULL;
          }
     pBuf->wNbLines = 0;
     pBuf->wLastIndex = 0;
     pBuf->pNext = 0;

     /*
     ** add this buffer to the end of the list.
     */
     if (pLast = DisFindLastBuffer(wType))
          pLast->pNext = pBuf;
     else Disasm[wType] = pBuf;
     return pBuf;
}

/*
** free all the buffers in a list.
*/
static void DisFreeList(WORD wType)
{
DIS_BUFFER *pBuf;

     /*
     ** add this buffer to the end of the list.
     */
     while (pBuf = Disasm[wType])
          {
          Disasm[wType] = pBuf->pNext;
          MemoryFree((BYTE *) pBuf);
          }
}

/*
** add a line into a buffer.
*/
static void DisAddLineInBuffer(char *szLine, DIS_BUFFER *pBuf)
{
     strcpy(pBuf->pDis + pBuf->wLastIndex, szLine);
     pBuf->wLastIndex += strlen(szLine) + 1;
     pBuf->wNbLines++;
}

/*
** free system and user label definitions.
*/
void DisResetLabelLines(HWND hWnd)
{
     DisFreeList(LABEL_SYSTEM);
     DisFreeList(LABEL_USER);
     if (hWnd)
          SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_REFRESH, 0, 0);
}

/*
** free code label definitions and code itself.
*/
void DisResetCodeLines(HWND hWnd)
{
     DisFreeList(LABEL_USER);
     DisFreeList(LABEL_CODE);
     DisFreeList(LABEL_NUMBER);
     if (hWnd)
          SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_REFRESH, 0, 0);
}

/*
** add a label definition into buffer.
*/
static BOOL DisAddLine(HWND hWnd, char *szLine, LABEL_ENUM wLabelType)
{
DIS_BUFFER *pBuf;
char szComment[40];

     /*
     ** allocate memory for label if not already done.
     */
     if ((pBuf = DisFindLastBuffer(wLabelType)) == NULL)
          {

          /*
          ** allocate a first buffer
          */
          if ((pBuf = DisAllocBuffer(hWnd, wLabelType)) == NULL)
               {
               Error(hWnd, IDS_ERR_NO_MEMORY, "Could not allocate memory !");
               return FALSE;
               }

          /*
          ** add the comment header.
          */
          DisAddLineInBuffer(Config.config10.szComment, pBuf);
          switch (wLabelType)
               {
               case LABEL_SYSTEM:
                    wsprintf(szComment, "%s System equates", Config.config10.szComment);
                    DisAddLineInBuffer(szComment, pBuf);
                    DisAddLineInBuffer(Config.config10.szComment, pBuf);
                    break;

               case LABEL_USER:
                    wsprintf(szComment, "%s User equates", Config.config10.szComment);
                    DisAddLineInBuffer(szComment, pBuf);
                    DisAddLineInBuffer(Config.config10.szComment, pBuf);
                    break;

               case LABEL_CODE:
                    wsprintf(szComment, "%s Code equates", Config.config10.szComment);
                    DisAddLineInBuffer(szComment, pBuf);
                    DisAddLineInBuffer(Config.config10.szComment, pBuf);
                    break;

               case LABEL_NUMBER:
                    wsprintf(szComment, "%s Start of code", Config.config10.szComment);
                    DisAddLineInBuffer(szComment, pBuf);
                    break;
               }
          }

     /*
     ** check if there is enough room in the last buffer allocated.
     */
     if (strlen(szLine) + pBuf->wLastIndex + 1 > DIS_MAX_BUFFER_SIZE)
          {

          /*
          ** allocate a new buffer
          */
          if ((pBuf = DisAllocBuffer(hWnd, wLabelType)) == NULL)
               {
               Error(hWnd, IDS_ERR_NO_MEMORY, "Could not allocate memory !");
               return FALSE;
               }
          }

     /*
     ** add line
     */
     DisAddLineInBuffer(szLine, pBuf);
     return TRUE;
}

/*
** add a label definition into buffer.
*/
BOOL DisAddLabel(HWND hWnd, char *szLabel, WORD wAddr, LABEL_ENUM wLabelType)
{
WORD wLen;

     /*
     ** build line.
     */
     strcpy(szErr, szLabel);
     if (Config.config10.bAlignInstructions)
          {
          for (wLen = strlen(szErr); wLen < 9; wLen++)
               szErr[wLen] = ' ';
          szErr[wLen] = 0;
          }
     else strcat(szErr, " ");
     if (Config.config10.bUseHex)
          wsprintf(szErr + strlen(szErr), "%s %s%04X", Config.config10.szEQU, Config.config10.szHex, wAddr);
     else wsprintf(szErr + strlen(szErr), "%s %u", Config.config10.szEQU, wAddr);

     /*
     ** add line to the label buffer.
     */
     return DisAddLine(hWnd, szErr, wLabelType);
}

/*
** add a label definition into buffer.
*/
BOOL DisAddComment(HWND hWnd, char *szComment, LABEL_ENUM wLabelType)
{
     /*
     ** build line.
     */
     wsprintf(szErr, "%s %s", Config.config10.szComment, szComment);

     /*
     ** add line to the label buffer.
     */
     return DisAddLine(hWnd, szErr, wLabelType);
}

/*
** save position of the new segment in the disassembly listing.
** Line 0 correspond to the first line of code.
*/
static void DisSavePosition(WORD wSegment)
{
DIS_BUFFER *pLast;
DWORD dwLineNum;

     /*
     ** add this buffer to the end of the list.
     */
     dwLineNum = 0;
     for (pLast = Disasm[LABEL_NUMBER]; pLast; pLast = pLast->pNext)
          dwLineNum += (DWORD) pLast->wNbLines;
     Segment[wSegment].dwLineNumber = dwLineNum + 1;
}

/*
** adjust position of all the segments in the disassembly listing.
** DisSavePosition has saved a line number relative to start of code.
** We have to add to every segment position the number of lines used by labels.
*/
static void DisAdjustPosition(void)
{
DIS_BUFFER *pLast;
DWORD dwLineNum;
WORD wSegment;
WORD wDis;

     /*
     ** add this buffer to the end of the list.
     */
     dwLineNum = 0;
     for (wDis = 0; wDis < LABEL_NUMBER; wDis++)
          for (pLast = Disasm[wDis]; pLast; pLast = pLast->pNext)
               dwLineNum += (DWORD) pLast->wNbLines;
     for (wSegment = 0; wSegment < MAX_SEGMENTS; wSegment++)
          if (Segment[wSegment].lpDump)
               Segment[wSegment].dwLineNumber += dwLineNum;
}

/*
** Give the user a chance to click on CANCEL button.
*/
static BOOL DisStop(void)
{
MSG msg;
static int cpt = 0;

     if ((cpt++ & 0x0F) == 0)
          {
          if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
               {
               TranslateMessage(&msg);
               DispatchMessage(&msg);
               }
          if (bDisCancel)
               {
               DisResetCodeLines(hMainWnd);
               InvalidateRect(hDisWnd, NULL, TRUE);
               LabelFreeCode();
               return TRUE;
               }
          }
     return FALSE;
}

/*
** initialize global variables to start of code.
*/
#define DIS_INIT(wSeg, wPC) \
     { char szBuf[10]; \
     wDisNbBytes = 0; \
     cDisDumpType = DUMP_TYPE_CODE; \
     wSeg = 0; \
     do   { \
          if ((Segment[wSeg].bBinary) && (pDisNextByte = Segment[wSeg].lpDump)) \
               { \
               pDisNextType = Segment[wSeg].lpType; \
               wPC = Segment[wSeg].wBegin; \
               wDisSegmentSize = Segment[wSeg].wEnd - wPC + 1; \
               bDisNewSegment = TRUE; \
               DisSavePosition(wSeg); \
               } \
          else if (++wSeg >= MAX_SEGMENTS) \
               break; \
          } \
     while (pDisNextByte == NULL); \
     wsprintf(szBuf, "%d", wSeg + 1); \
     SendDlgItemMessage(hWnd, IDC_SEGMENT_NUMBER, WM_SETTEXT, 0, (LPARAM) (LPCSTR) szBuf); \
     }

/*
** returns next byte of code in cByte and increment wPC which is the address of the byte.
** If a segment limit has been crossed (the new segment is not contiguous with the
** previous one), bDisNewSegment is set. The kind of byte is set in cDisByteType.
** pDisNextByte is incremented. At the end of the code, the last byte is returned
** and pDisNextByte is NULL.
*/
#define DIS_GET_NEXT_BYTE(cByte, wSeg, wPC) \
     { \
     cByte = *pDisNextByte++; \
     cDisByteType = *pDisNextType++; \
     if (--wDisSegmentSize == 0) \
          { WORD wLastEnd = Segment[wSeg].wEnd; \
          pDisNextByte = pDisNextType = NULL; \
          do   { \
               if (++wSeg >= MAX_SEGMENTS) \
                    break; \
               if (Segment[wSeg].bBinary) \
                    if (pDisNextByte = Segment[wSeg].lpDump) \
                         { char szBuf[10]; \
                         pDisNextType = Segment[wSeg].lpType; \
                         wsprintf(szBuf, "%d", wSeg + 1); \
                         SendDlgItemMessage(hWnd, IDC_SEGMENT_NUMBER, WM_SETTEXT, 0, (LPARAM) (LPCSTR) szBuf); \
                         wPC = Segment[wSeg].wBegin; \
                         wDisSegmentSize = Segment[wSeg].wEnd - wPC + 1; \
                         if (wLastEnd + 1 != wPC) \
                              bDisNewSegment = TRUE; \
                         DisSavePosition(wSeg); \
                         } \
               } \
          while (pDisNextByte == NULL); \
          } \
     else wPC++; \
     if (DisStop()) \
          return; \
     }

/*
** returns next byte in cLow for Pass 1.
*/
#define DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC) \
     { \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          break; \
     DIS_GET_NEXT_BYTE(cLow, wSeg, wPC); \
     }

/*
** returns next word in wAddr for Pass 1.
*/
#define DIS_GET_WORD_IN_PASS_1(wAddr, wSeg, wPC) \
     { BYTE cL, cH; \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          break; \
     DIS_GET_NEXT_BYTE(cL, wSeg, wPC); \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          break; \
     DIS_GET_NEXT_BYTE(cH, wSeg, wPC); \
     wAddr = ((WORD) cL) | (((WORD) cH) << 8); \
     }

/*
** flush dump .BYTE directive in the disassembly listing.
*/
#define DIS_FLUSH_BYTES(hWnd, szBytes) \
     { \
     if (wDisNbBytes) \
          { \
          switch (cDisDumpType) \
               { \
               case DUMP_TYPE_STRING: \
               case DUMP_TYPE_SBYTE: \
                    strcat(szBytes, "\""); \
                    break; \
               case DUMP_TYPE_STORE: \
                    wsprintf(szBytes + strlen(szBytes), "%d", wDisNbBytes); \
                    break; \
               } \
          DisAddLine(hWnd, szBytes, LABEL_NUMBER); \
          szBytes[0] = 0; \
          wDisNbBytes = 0; \
          cDisDumpType = DUMP_TYPE_CODE; \
          } \
     }

/*
** skip another byte with a .DS directive.
*/
#define DIS_DUMP_STORE(hWnd) \
     { \
     if (cDisDumpType != DUMP_TYPE_STORE) \
          DIS_FLUSH_BYTES(hWnd, szBytes) \
     cDisDumpType = DUMP_TYPE_STORE; \
     if (wDisNbBytes == 0) \
          wsprintf(szBytes, "%s%s ", szErr, Config.szDS); \
     wDisNbBytes++; \
     }

/*
** save a byte in a temporary buffer. This byte will be written in a .BYTE directive
** in an hexadecimal format.
*/
#define DIS_DUMP_BYTE(hWnd, szBytes, cByte) \
     { \
     if (wDisNbBytes >= wConfigNbBytesPerLine) \
          DIS_FLUSH_BYTES(hWnd, szBytes) \
     else { \
          if (cDisDumpType != DUMP_TYPE_BYTE) \
               DIS_FLUSH_BYTES(hWnd, szBytes) \
          } \
     cDisDumpType = DUMP_TYPE_BYTE; \
     if (Config.config10.bUseHex) \
          { \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s %s%02X", szErr, Config.config10.szBYTE, Config.config10.szHex, cByte); \
          else wsprintf(szBytes + strlen(szBytes), "%s%s%02X", Config.config10.szByteSeparator, Config.config10.szHex, cByte); \
          } \
     else { \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s %u", szErr, Config.config10.szBYTE, cByte); \
          else wsprintf(szBytes + strlen(szBytes), "%s%u", Config.config10.szByteSeparator, cByte); \
          } \
     wDisNbBytes++; \
     }

/*
** save a byte in a temporary buffer. This byte will be written in a .BYTE directive
** in a string format.
*/
#define DIS_DUMP_STRING(hWnd, szBytes, cByte) \
     { \
     if ((cByte == cReturn) || (cByte == 0x22) || (cByte == 0)) \
          DIS_DUMP_BYTE(hWnd, szBytes, cByte) \
     else { \
          if (wDisNbBytes >= wConfigNbCharPerString) \
               DIS_FLUSH_BYTES(hWnd, szBytes) \
          else { \
               if (cDisDumpType != DUMP_TYPE_STRING) \
                    DIS_FLUSH_BYTES(hWnd, szBytes) \
               } \
          cDisDumpType = DUMP_TYPE_STRING; \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s \"%c", szErr, Config.config10.szBYTE, cByte); \
          else { int len; \
               len = strlen(szBytes); \
               szBytes[len] = cByte; \
               szBytes[len + 1] = 0; \
               } \
          wDisNbBytes++; \
          } \
     }

/*
** save a byte in a temporary buffer. This byte will be written in a .SBYTE directive
** in a string format containing internal code.
*/
#define DIS_DUMP_SBYTE(hWnd, szBytes, cByte) \
     { BYTE cInternal; \
     cInternal = cByte; \
     if (cInternal < 64) \
          cInternal += 32; \
     else if (cInternal < 96) \
          cInternal -= 64; \
     else if ((cInternal >= 128) && (cInternal < 128 + 64)) \
          cInternal += 32; \
     else if ((cInternal >= 128 + 64) && (cInternal < 128 + 96)) \
          cInternal -= 64; \
     if ((cInternal == cReturn) || (cInternal == 0x22) || (cInternal == 0)) \
          DIS_DUMP_BYTE(hWnd, szBytes, cByte) \
     else { \
          if (wDisNbBytes >= wConfigNbCharPerString) \
               DIS_FLUSH_BYTES(hWnd, szBytes) \
          else { \
               if (cDisDumpType != DUMP_TYPE_SBYTE) \
                    DIS_FLUSH_BYTES(hWnd, szBytes) \
               } \
          cDisDumpType = DUMP_TYPE_SBYTE; \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s \"%c", szErr, Config.config10.szSBYTE, cInternal); \
          else { int len; \
               len = strlen(szBytes); \
               szBytes[len] = cInternal; \
               szBytes[len + 1] = 0; \
               } \
          wDisNbBytes++; \
          } \
     }

/*
** save a word in a temporary buffer. This word will be written in a .WORD directive
** in an hexadecimal format.
*/
#define DIS_DUMP_WORD(hWnd, szBytes, wAddr) \
     { \
     if (wDisNbBytes >= wConfigNbWordsPerLine) \
          DIS_FLUSH_BYTES(hWnd, szBytes) \
     else { \
          if (cDisDumpType != DUMP_TYPE_WORD) \
               DIS_FLUSH_BYTES(hWnd, szBytes) \
          } \
     cDisDumpType = DUMP_TYPE_WORD; \
     if (Config.config10.bUseHex) \
          { \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s %s%04X", szErr, Config.config10.szWORD, Config.config10.szHex, wAddr); \
          else wsprintf(szBytes + strlen(szBytes), "%s%s%04X", Config.config10.szByteSeparator, Config.config10.szHex, wAddr); \
          } \
     else { \
          if (wDisNbBytes == 0) \
               wsprintf(szBytes, "%s%s %u", szErr, Config.config10.szWORD, wAddr); \
          else wsprintf(szBytes + strlen(szBytes), "%s%u", Config.config10.szByteSeparator, wAddr); \
          } \
     wDisNbBytes++; \
     }

/*
** save a label in a temporary buffer. This label will be written in a .WORD directive.
*/
#define DIS_DUMP_LABEL(hWnd, szBytes, szLabel) \
     { \
     if (wDisNbBytes >= wConfigNbWordsPerLine) \
          DIS_FLUSH_BYTES(hWnd, szBytes) \
     else { \
          if (cDisDumpType != DUMP_TYPE_LABEL) \
               DIS_FLUSH_BYTES(hWnd, szBytes) \
          } \
     cDisDumpType = DUMP_TYPE_LABEL; \
     if (wDisNbBytes == 0) \
          wsprintf(szBytes, "%s%s %s", szErr, Config.config10.szWORD, szLabel); \
     else wsprintf(szBytes + strlen(szBytes), "%s%s", Config.config10.szByteSeparator, szLabel); \
     wDisNbBytes++; \
     }

/*
** add a line of code to the disassembly listing but, first, flush any pending .BYTE
** directive.
*/
#define DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szLine) \
     { \
     DIS_FLUSH_BYTES(hWnd, szBytes); \
     DisAddLine(hWnd, szLine, LABEL_NUMBER); \
     }

/*
** returns next byte in cLow for Pass 2.
*/
#define DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC) \
     { \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          { \
          DIS_DUMP_BYTE(hWnd, szBytes, cByte); \
          break; \
          } \
     DIS_GET_NEXT_BYTE(cLow, wSeg, wPC); \
     }

/*
** returns next word in wAddr for Pass 2.
*/
#define DIS_GET_WORD_IN_PASS_2(hWnd, szBytes, cByte, wAddr, wSeg, wPC) \
     { BYTE cL, cH; \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          { \
          DIS_DUMP_BYTE(hWnd, szBytes, cByte); \
          break; \
          } \
     DIS_GET_NEXT_BYTE(cL, wSeg, wPC); \
     if (bDisNewSegment || (pDisNextByte == NULL)) \
          { \
          DIS_DUMP_BYTE(hWnd, szBytes, cByte); \
          DIS_DUMP_BYTE(hWnd, szBytes, cL); \
          break; \
          } \
     DIS_GET_NEXT_BYTE(cH, wSeg, wPC); \
     wAddr = ((WORD) cL) | (((WORD) cH) << 8); \
     }

/*
** Pass 1: reserve all labels.
*/
static void DisPass1(HWND hWnd)
{
BYTE cByte;
BYTE cLow;
WORD wAddr;
WORD wPC;
WORD wSeg;

     DIS_INIT(wSeg, wPC);
     while (pDisNextByte)
          {
          bDisNewSegment = FALSE;
          DIS_GET_NEXT_BYTE(cByte, wSeg, wPC);
          switch (cDisByteType)
               {

               /*
               ** no label: this is a byte.
               */
               case DUMP_TYPE_BYTE:
               case DUMP_TYPE_STRING:
               case DUMP_TYPE_SBYTE:
               case DUMP_TYPE_STORE:
                    break;

               /*
               ** no label: this is a word.
               */
               case DUMP_TYPE_WORD:
                    DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                    break;

               /*
               ** this is a label
               */
               case DUMP_TYPE_LABEL:
                    DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                    wAddr = ((WORD) cByte) | (((WORD) cLow) << 8);
                    if (LabelAddCode(hWnd, wAddr, TRUE) == FALSE)
                         return;
                    break;

               /*
               ** there may be a label: this is the display list.
               */
               case DUMP_TYPE_DLIST:
                    switch (cByte & 0x0F)
                         {

                         /*
                         ** empty lines
                         */
                         case 0:
                              break;

                         /*
                         ** jump
                         */
                         case 1:
                              DIS_GET_WORD_IN_PASS_1(wAddr, wSeg, wPC);
                              if (LabelAddCode(hWnd, wAddr, TRUE) == FALSE)
                                   return;
                              break;

                         /*
                         ** graphic lines
                         */
                         default:

                              /*
                              ** Load Memory Scan
                              */
                              if (cByte & 0x40)
                                   {
                                   DIS_GET_WORD_IN_PASS_1(wAddr, wSeg, wPC);
                                   if (LabelAddCode(hWnd, wAddr, TRUE) == FALSE)
                                        return;
                                   }
                              break;
                         }
                    break;

               /*
               ** code.
               */
               case DUMP_TYPE_LOBYTE:
               case DUMP_TYPE_HIBYTE:
               case DUMP_TYPE_CODE:
                    if ((TabOpcode[cByte].bIllegal == TRUE) && (Config.config10.bIllegalOpcodes == FALSE))
                         break;
                    switch (TabOpcode[cByte].wMode)
                         {
     
                         /*
                         ** get absolute address.
                         */
                         case MODE_ABSOLUTE:
                         case MODE_INDIRECT:
                         case MODE_ABSOLUTE_X:
                         case MODE_ABSOLUTE_Y:
                              DIS_GET_WORD_IN_PASS_1(wAddr, wSeg, wPC);
                              if (LabelAddCode(hWnd, wAddr, TRUE) == FALSE)
                                   return;
                              break;
     
                         /*
                         ** get zero-page absolute address.
                         */
                         case MODE_ZERO_PAGE_X:
                         case MODE_ZERO_PAGE_Y:
                         case MODE_ZERO_PAGE:
                         case MODE_INDEXED_INDIRECT:
                         case MODE_INDIRECT_INDEXED:
                              DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                              if (LabelAddCode(hWnd, (WORD) cLow, TRUE) == FALSE)
                                   return;
                              break;
     
                         /*
                         ** get relative address and make an absolute one.
                         */
                         case MODE_RELATIVE:
                              DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                              if (cLow > 127)
                                   wAddr = wPC + (WORD) cLow - 256;
                              else wAddr = wPC + (WORD) cLow;
                              if (LabelAddCode(hWnd, wAddr, FALSE) == FALSE)
                                   return;
                              break;

                         /*
                         ** other modes with a parameter that is not an address.
                         */
                         case MODE_IMMEDIATE:
                              if (cDisByteType == DUMP_TYPE_LOBYTE)
                                   {
                                   DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                                   wAddr = ((WORD) cLow) | (((WORD) cDisByteType) << 8);
                                   if (LabelAddCode(hWnd, (WORD) wAddr, TRUE) == FALSE)
                                        return;
                                   }
                              else if (cDisByteType == DUMP_TYPE_HIBYTE)
                                   {
                                   DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                                   wAddr = ((WORD) cDisByteType) | (((WORD) cLow) << 8);
                                   if (LabelAddCode(hWnd, (WORD) wAddr, TRUE) == FALSE)
                                        return;
                                   }
                              else DIS_GET_BYTE_IN_PASS_1(cLow, wSeg, wPC);
                              break;
                         }
                    break;

               /*
               ** default is an error.
               */
               default:
                    Error(hWnd, IDS_ERR_BAD_TYPE, "The byte type %u at address $%04X is unknown (internal error) !", cDisByteType, wPC);
                    return;
               }
          }
}

/*
** Pass 2: generate listing
*/
static void DisPass2(HWND hWnd)
{
BYTE cByte;
BYTE cLow;
WORD wAddr;
WORD wPC;
WORD wSeg;
WORD wLen;
BOOL bAnticLabel;
/*LABEL_FLAG bLabelFlag;*/
char *szLabel;
static char szBytes[256];

     DIS_INIT(wSeg, wPC);
     bAnticLabel = FALSE;
     while (pDisNextByte)
          {
          if (bDisNewSegment)
               {
               bDisNewSegment = FALSE;
               DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, Config.config10.szComment);
               if (Config.config10.bAlignInstructions)
                    strcpy(szErr, "         ");
               else szErr[0] = 0;
               /*if (szLabel = LabelFindEquate(wPC, &bLabelFlag))
                    wsprintf(szErr + strlen(szErr), "%s %s", Config.config10.szORG, szLabel);
               else*/ {
                    if (Config.config10.bUseHex)
                         wsprintf(szErr + strlen(szErr), "%s %s%04X", Config.config10.szORG, Config.config10.szHex, wPC);
                    else wsprintf(szErr + strlen(szErr), "%s %u", Config.config10.szORG, wPC);
                    }
               DisAddLine(hWnd, szErr, LABEL_NUMBER);
               DisAddLine(hWnd, Config.config10.szComment, LABEL_NUMBER);
               }
          if (szLabel = LabelReserve(wPC))
               {
               DIS_FLUSH_BYTES(hWnd, szBytes);
               LabelDeleteCodeUsed(wPC);
               strcpy(szErr, szLabel);
               if (Config.config10.bAlignInstructions)
                    {
                    wLen = strlen(szErr);
                    for (szLabel = szErr + wLen; wLen < 9; wLen++)
                         *szLabel++ = ' ';
                    *szLabel = 0;
                    }
               else strcat(szErr, " ");
               }
          else {
               if (Config.config10.bAlignInstructions)
                    strcpy(szErr, "         ");
               else szErr[0] = 0;
               }
          DIS_GET_NEXT_BYTE(cByte, wSeg, wPC);
          if (cDisByteType != DUMP_TYPE_DLIST)
               bAnticLabel = FALSE;
          switch (cDisByteType)
               {

               /*
               ** N bytes skipped in memory (data storage)
               */
               case DUMP_TYPE_STORE:
                    if (Config.bDSAllowed)
                         DIS_DUMP_STORE(hWnd)
                    else DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                    break;

               /*
               ** one byte in hexadecimal format
               */
               case DUMP_TYPE_BYTE:
                    DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                    break;

               /*
               ** one byte in string format
               */
               case DUMP_TYPE_STRING:
                    DIS_DUMP_STRING(hWnd, szBytes, cByte);
                    break;

               /*
               ** one byte in internal format
               */
               case DUMP_TYPE_SBYTE:
                    if (Config.config10.bSByteAllowed)
                         DIS_DUMP_SBYTE(hWnd, szBytes, cByte)
                    else DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                    break;

               /*
               ** two bytes in a WORD (MSB first)
               */
               case DUMP_TYPE_WORD:
                    DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                    if (Config.config10.bWordAllowed)
                         {
                         wAddr = ((WORD) cByte) | (((WORD) cLow) << 8);
                         DIS_DUMP_WORD(hWnd, szBytes, wAddr);
                         }
                    else {
                         DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                         DIS_DUMP_BYTE(hWnd, szBytes, cLow);
                         }
                    break;

               /*
               ** a label (absolute address)
               */
               case DUMP_TYPE_LABEL:
                    DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                    if (Config.config10.bWordAllowed)
                         {
                         wAddr = ((WORD) cByte) | (((WORD) cLow) << 8);
                         if ((Config.config10.bNumOnlyInByte == FALSE) && (szLabel = LabelFind(wAddr)))
                              DIS_DUMP_LABEL(hWnd, szBytes, szLabel)
                         else DIS_DUMP_WORD(hWnd, szBytes, wAddr)
                         }
                    else {
                         DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                         DIS_DUMP_BYTE(hWnd, szBytes, cLow);
                         }
                    break;

               /*
               ** this is the display list.
               */
               case DUMP_TYPE_DLIST:
                    if (Config.config10.bNumOnlyInByte)
                         DIS_DUMP_BYTE(hWnd, szBytes, cByte)
                    else {
                         if (bAnticLabel)
                              {
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (Config.config10.bWordAllowed)
                                   {
                                   wAddr = ((WORD) cByte) | (((WORD) cLow) << 8);
                                   if (szLabel = LabelFind(wAddr))
                                        DIS_DUMP_LABEL(hWnd, szBytes, szLabel)
                                   else DIS_DUMP_WORD(hWnd, szBytes, wAddr)
                                   }
                              else {
                                   DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                                   DIS_DUMP_BYTE(hWnd, szBytes, cLow);
                                   }
                              bAnticLabel = FALSE;
                              }
                         else switch (cByte & 0x0F)
                              {

                              /*
                              ** empty lines
                              */
                              case 0:
                                   wsprintf(szErr + strlen(szErr), "%s %sAEMPTY%d", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""), ((cByte & 0x70) >> 4) + 1);
                                   DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                                   break;

                              /*
                              ** jump
                              */
                              case 1:
                                   wsprintf(szErr + strlen(szErr), "%s %s%sAJMP", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""), ((cByte & 0x40) ? "AVB+" : ""));
                                   DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                                   bAnticLabel = TRUE;
                                   break;

                              /*
                              ** graphic lines
                              */
                              default:

                                   /*
                                   ** Load Memory Scan
                                   */
                                   if (cByte & 0x40)
                                        {
                                        if (Config.config10.bUseHex)
                                             wsprintf(szErr + strlen(szErr), "%s %s%s%sALMS+%s%02X", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""),
                                                      ((cByte & 0x20) ? "AVSCR+" : ""), ((cByte & 0x20) ? "AHSCR+" : ""), Config.config10.szHex, cByte & 0x0F);
                                        else wsprintf(szErr + strlen(szErr), "%s %s%s%sALMS+%u", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""),
                                                      ((cByte & 0x20) ? "AVSCR+" : ""), ((cByte & 0x20) ? "AHSCR+" : ""), cByte & 0x0F);
                                        DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                                        bAnticLabel = TRUE;
                                        }
                                   else {
                                        if (cByte & 0xF0)
                                             {
                                             if (Config.config10.bUseHex)
                                                  wsprintf(szErr + strlen(szErr), "%s %s%s%s%s%02X", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""),
                                                           ((cByte & 0x20) ? "AVSCR+" : ""), ((cByte & 0x20) ? "AHSCR+" : ""), Config.config10.szHex, cByte & 0x0F);
                                             else wsprintf(szErr + strlen(szErr), "%s %s%s%s%u", Config.config10.szBYTE, ((cByte & 0x80) ? "ADLI+" : ""),
                                                           ((cByte & 0x20) ? "AVSCR+" : ""), ((cByte & 0x20) ? "AHSCR+" : ""), cByte & 0x0F);
                                             DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                                             }
                                        else DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                                        }
                                   break;
                              }
                         }
                    break;

               /*
               ** code.
               */
               case DUMP_TYPE_LOBYTE:
               case DUMP_TYPE_HIBYTE:
               case DUMP_TYPE_CODE:
                    if ((TabOpcode[cByte].bIllegal == TRUE) && (Config.config10.bIllegalOpcodes == FALSE))
                         {
                         DIS_DUMP_BYTE(hWnd, szBytes, cByte);
                         break;
                         }
                    switch (TabOpcode[cByte].wMode)
                         {
                         case MODE_IMMEDIATE:
                              if (cDisByteType == DUMP_TYPE_LOBYTE)
                                   {
                                   DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                                   wAddr = ((WORD) cLow) | (((WORD) cDisByteType) << 8);
                                   if (szLabel = LabelFind(wAddr))
                                        wsprintf(szErr + strlen(szErr), "%s #%s%s%s", TabOpcode[cByte].szName, Config.config10.szLOWHead, szLabel, Config.config10.szLOWTail);
                                   else {
                                        if (Config.config10.bUseHex)
                                             wsprintf(szErr + strlen(szErr), "%s #%s%02X", TabOpcode[cByte].szName, Config.config10.szHex, cLow);
                                        else wsprintf(szErr + strlen(szErr), "%s #%u", TabOpcode[cByte].szName, cLow);
                                        }
                                   }
                              else if (cDisByteType == DUMP_TYPE_HIBYTE)
                                   {
                                   DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                                   wAddr = ((WORD) cDisByteType) | (((WORD) cLow) << 8);
                                   if (szLabel = LabelFind(wAddr))
                                        wsprintf(szErr + strlen(szErr), "%s #%s%s%s", TabOpcode[cByte].szName, Config.config10.szHIGHHead, szLabel, Config.config10.szHIGHTail);
                                   else {
                                        if (Config.config10.bUseHex)
                                             wsprintf(szErr + strlen(szErr), "%s #%s%02X", TabOpcode[cByte].szName, Config.config10.szHex, cLow);
                                        else wsprintf(szErr + strlen(szErr), "%s #%u", TabOpcode[cByte].szName, cLow);
                                        }
                                   }
                              else {
                                   DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s #%s%02X", TabOpcode[cByte].szName, Config.config10.szHex, cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s #%u", TabOpcode[cByte].szName, cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ABSOLUTE:
                              DIS_GET_WORD_IN_PASS_2(hWnd, szBytes, cByte, wAddr, wSeg, wPC);
                              if (szLabel = LabelFind(wAddr))
                                   wsprintf(szErr + strlen(szErr), "%s %s", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%04X", TabOpcode[cByte].szName, Config.config10.szHex, wAddr);
                                   else wsprintf(szErr + strlen(szErr), "%s %u", TabOpcode[cByte].szName, wAddr);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ZERO_PAGE:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (szLabel = LabelFind((WORD) cLow))
                                   wsprintf(szErr + strlen(szErr), "%s %s", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%02X", TabOpcode[cByte].szName, Config.config10.szHex, (WORD) cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s %u", TabOpcode[cByte].szName, (WORD) cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ACCUMULATOR:
                              wsprintf(szErr + strlen(szErr), "%s%s", TabOpcode[cByte].szName, (Config.config10.bShowAforImplicite ? " A" : ""));
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_IMPLIED:
                              wsprintf(szErr + strlen(szErr), "%s", TabOpcode[cByte].szName);
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_INDEXED_INDIRECT:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (szLabel = LabelFind((WORD) cLow))
                                   wsprintf(szErr + strlen(szErr), "%s (%s,X)", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s (%s%02X,X)", TabOpcode[cByte].szName, Config.config10.szHex, (WORD) cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s (%u,X)", TabOpcode[cByte].szName, (WORD) cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_INDIRECT_INDEXED:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (szLabel = LabelFind((WORD) cLow))
                                   wsprintf(szErr + strlen(szErr), "%s (%s),Y", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s (%s%02X),Y", TabOpcode[cByte].szName, Config.config10.szHex, (WORD) cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s (%u),Y", TabOpcode[cByte].szName, (WORD) cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ZERO_PAGE_X:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (szLabel = LabelFind((WORD) cLow))
                                   wsprintf(szErr + strlen(szErr), "%s %s,X", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%02X,X", TabOpcode[cByte].szName, Config.config10.szHex, (WORD) cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s %u,X", TabOpcode[cByte].szName, (WORD) cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ZERO_PAGE_Y:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (szLabel = LabelFind((WORD) cLow))
                                   wsprintf(szErr + strlen(szErr), "%s %s,Y", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%02X,Y", TabOpcode[cByte].szName, Config.config10.szHex, (WORD) cLow);
                                   else wsprintf(szErr + strlen(szErr), "%s %u,Y", TabOpcode[cByte].szName, (WORD) cLow);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ABSOLUTE_X:
                              DIS_GET_WORD_IN_PASS_2(hWnd, szBytes, cByte, wAddr, wSeg, wPC);
                              if (szLabel = LabelFind(wAddr))
                                   wsprintf(szErr + strlen(szErr), "%s %s,X", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%04X,X", TabOpcode[cByte].szName, Config.config10.szHex, wAddr);
                                   else wsprintf(szErr + strlen(szErr), "%s %u,X", TabOpcode[cByte].szName, wAddr);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_ABSOLUTE_Y:
                              DIS_GET_WORD_IN_PASS_2(hWnd, szBytes, cByte, wAddr, wSeg, wPC);
                              if (szLabel = LabelFind(wAddr))
                                   wsprintf(szErr + strlen(szErr), "%s %s,Y", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%04X,Y", TabOpcode[cByte].szName, Config.config10.szHex, wAddr);
                                   else wsprintf(szErr + strlen(szErr), "%s %u,Y", TabOpcode[cByte].szName, wAddr);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_RELATIVE:
                              DIS_GET_BYTE_IN_PASS_2(hWnd, szBytes, cByte, cLow, wSeg, wPC);
                              if (cLow > 127)
                                   wAddr = wPC + (WORD) cLow - 256;
                              else wAddr = wPC + (WORD) cLow;
                              if (szLabel = LabelFind(wAddr))
                                   wsprintf(szErr + strlen(szErr), "%s %s", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s %s%04X", TabOpcode[cByte].szName, Config.config10.szHex, wAddr);
                                   else wsprintf(szErr + strlen(szErr), "%s %u", TabOpcode[cByte].szName, wAddr);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
               
                         case MODE_INDIRECT:
                              DIS_GET_WORD_IN_PASS_2(hWnd, szBytes, cByte, wAddr, wSeg, wPC);
                              if (szLabel = LabelFind(wAddr))
                                   wsprintf(szErr + strlen(szErr), "%s (%s)", TabOpcode[cByte].szName, szLabel);
                              else {
                                   if (Config.config10.bUseHex)
                                        wsprintf(szErr + strlen(szErr), "%s (%s%04X)", TabOpcode[cByte].szName, Config.config10.szHex, wAddr);
                                   else wsprintf(szErr + strlen(szErr), "%s (%u)", TabOpcode[cByte].szName, wAddr);
                                   }
                              DIS_FLUSH_AND_ADD_LINE(hWnd, szBytes, szErr);
                              break;
                         }
                    break;

               /*
               ** default is an error.
               */
               default:
                    Error(hWnd, IDS_ERR_BAD_TYPE, "The byte type %u at address $%04X is unknown (internal error) !", cDisByteType, wPC);
                    return;
               }
          }
     DIS_FLUSH_BYTES(hWnd, szBytes);
}

static void Disassemble(HWND hWnd)
{
     /*
     ** pass 1: reserve all labels.
     */
     SendDlgItemMessage(hWnd, IDC_PASS_NUMBER, WM_SETTEXT, 0, (LPARAM) (LPCSTR) "1");
     LabelUserSetFlag(LABEL_FLAG_UNREFERENCED);
     DisPass1(hWnd);

     /*
     ** sort all labels.
     */
     SendDlgItemMessage(hWnd, IDC_SEGMENT_NUMBER, WM_SETTEXT, 0, (LPARAM) (LPCSTR) "     ");
     LabelSortCode();

     /*
     ** pass 2: generate listing.
     */
     SendDlgItemMessage(hWnd, IDC_PASS_NUMBER, WM_SETTEXT, 0, (LPARAM) (LPCSTR) "2");
     DisPass2(hWnd);

     /*
     ** generate labels that have not been defined in the code listing.
     */
     LabelDumpCode(hWnd);
     DisAdjustPosition();
/*
     DisAddLine(hWnd, Config.szComment, LABEL_NUMBER);
     if (Config.bAlignInstructions)
          wsprintf(szBytes, "         %s%s%s", Config.szENDHead, (Config.bEndNeedFilename ? "source.asm" : ""), Config.szENDTail);
     else wsprintf(szBytes, "%s%s%s", Config.szENDHead, (Config.bEndNeedFilename ? "source.asm" : ""), Config.szENDTail);
     DisAddLine(hWnd, szBytes, LABEL_NUMBER);
*/
}

/*
** let the screen be refreshed.
*/
static void DisRedrawScreen(HWND hDlg)
{
MSG msg;

     SetCapture(hDlg);
     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
          {
          TranslateMessage(&msg);
          DispatchMessage(&msg);
          }
     ReleaseCapture();
}

/*
** call disassembly process while displaying a dialog box.
** The user can click on CANCEL to abort the process.
*/
BOOL __export CALLBACK DisProcessProc(HWND hDlg, UINT message, WORD wParam, LONG lParam)
{
     switch (message)
          {
          case WM_INITDIALOG:
               DisRedrawScreen(hDlg);
               PostMessage(hDlg, WM_USER + 4321, 0, 0L);
               return TRUE;

          case WM_USER + 4321:
               bDisCancel = FALSE;
               Disassemble(hDlg);
               EndDialog(hDlg, TRUE);
               return TRUE;

          case WM_COMMAND:
               if (wParam == IDCANCEL)
                    bDisCancel = TRUE;
          }
     return FALSE;
}

/*
** scroll to a specific line in the disassembly listing.
*/
void DisSelectLine(HWND hWnd, DWORD dwLineNumber, BOOL bRefresh)
{
     SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_SET_BUFFER, MAX_DISASM, (LPARAM) (LPVOID) &Disasm);
     SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_SET_SCROLL, bRefresh, (LPARAM) dwLineNumber);
}

/*
** start disassembly by opening the dialog box that shows the process.
*/
void DisProcess(HANDLE hInstance, HWND hWnd)
{
     DialogBox(hInstance, "DISPROCESSBOX", hWnd, DisProcessProc);
     DisSelectLine(hMainWnd, Segment[wDumpSegment].dwLineNumber, TRUE);
}

/*
** redraw disassembly window
*/
void DisRefresh(HWND hWnd)
{
     SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_SET_LINENUM, Config.config10.bLineNumbering, FALSE);
     SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_SET_BUFFER, MAX_DISASM, (LPARAM) (LPVOID) &Disasm);
     InvalidateRect(GetDlgItem(hWnd, ID_DIS), NULL, TRUE);
}

/*
** remove all code lines and update window.
*/
void DisReset(HWND hWnd)
{
     DisResetCodeLines(hWnd);
     if (hWnd)
          {
          DisRefresh(hWnd);
          SendDlgItemMessage(hWnd, ID_DIS, WM_DIS_SET_SCROLL, FALSE, 0);
          }
}

/*
** returns the mode for an instruction opcode
*/
BOOL DisIsImmediateMode(BYTE cOpcode)
{
     return TabOpcode[cOpcode].wMode == MODE_IMMEDIATE;
}
